<template>
	<!-- my-tars 是一个通用的组件，可以提供给其他项目使用
	1. 可以在父组件中定制样式
	2. 可以在父组件中指定数据
	3. 可以在父组件中选中项
	-->
	<view class="tab-container">
		<view class="tab-box">
			<scroll-view scroll-x class="scroll-view" scroll-with-animation :scroll-left="scrollLeft">
				<view class="scroll-content">
					<view class="tab-item-box">
						<!-- block 块级元素，与之对应的是行级元素 -->
						<block v-for="(item, index) in tabData" :key="index">
							<!-- || 如果没有label，就取item本身 -->
							<view :id="'_tab_' + index" class="tab-item"
								:class="{ 'tab-item-active': activeIndex === index }" @click="onTabClick(index)"
								:style="{ color: activeIndex === index ? defaultConfig.activeTextColor : defaultConfig.textColor }">
								{{ item.label || item }}
							</view>
						</block>
					</view>
					<view class="under-line" :style="{
						transform: 'translateX(' + slider.left + 'px)',
						width: defaultConfig.underLineWidth + 'px',
						height: defaultConfig.underLineHeight + 'px',
						backgroundColor: defaultConfig.underLineColor
					}">
					</view>
				</view>
			</scroll-view>
		</view>
	</view>
</template>

<script>
export default {
	name: "my-tabs",
	props: {
		// 1. 可以在父组件中定制样式
		// 配置对象
		config: {
			type: Object,
			// default 如果是复杂数据类型，那么需要指定value为一个函数，通过 返回值的形式指定默认值
			default: () => {
				return {};
			}
		},
		// 2. 可以在父组件中指定数据
		tabData: {
			type: Array,
			default: () => {
				return [];
			}
		},
		// 3. 可以在父组件中选中项
		// 父组件传递的数据，我们不应该在子组件中修改
		defaultIndex: {
			type: Number,
			default: 0
		}
	},
	data() {
		return {
			// 内部维护的数据对象，为每个 item 单独维护一个 slider 的滑块对象
			tabList: [],
			// 当前激活项的index
			activeIndex: -1,
			// 滑块
			slider: {
				// 滑块距离左侧的距离
				left: 0
			},
			// scrollView 的横向滚动条位置
			scrollLeft: 0,
			// 默认配置
			defaultConfig: {
				// 默认的字体颜色
				textColor: '#333333',
				// 高亮的字体颜色
				activeTextColor: '#f94d2a',
				// 下划线宽度，高度，颜色
				underLineWidth: 24,
				underLineHeight: 2,
				underLineColor: 'orangered'
			}
		};
	},
	// 监听器
	watch: {
		// 监听 config 的变化
		config: {
			// 当 config 发生变化时,回调的方法
			handler(val) {
				// 使传入的数据覆盖 defaultConfig 的属性
				this.defaultConfig = { ...this.defaultConfig, ...val }
			},
			// 当前的 handler 回调将在侦听开始之后立即被调用
			immediate: true
		},
		// 监听 tabData 的变化
		tabData: {
			// 当 tabData 发生变化时,回调的方法
			handler(val) {
				// tabList 数据已经和 tabData 同步了
				this.tabList = val;
				// 维护 tabList 中的每个 item，为 DOM 渲染完成之后
				// 因为存在兼容性问题，不用this.$nextTick()（将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它，然后等待 DOM 更新。)
				setTimeout(() => {
					// 计算 item 的 slider
					this.updateTabWidth();
				}, 0);
			},
			// 当前的 handler 回调将在侦听开始之后立即被调用
			immediate: true
		},
		// 监听激活项目的变化
		defaultIndex: {
			// 当 defaultIndex 发生变化时,回调的方法
			handler(val) {
				this.activeIndex = val;
				// 重新计算滑块的位置
				this.tabToIndex();
			},
			// 当前的 handler 回调将在侦听开始之后立即被调用
			immediate: true
		}
	},
	methods: {
		// 更新 tab 的宽度
		updateTabWidth() {
			let data = this.tabList;
			if (data.length === 0) return;
			// uniapp 中拿到渲染之后的 dom 固定写法
			const query = uni.createSelectorQuery().in(this);
			data.forEach((item, index) => {
				// 获取 dom
				query.select('#_tab_' + index).boundingClientRect((res) => {
					// res 就是拿到的 dom，为数据对象的每个 item 都维护一个 _slider 对象
					item._slider = {
						left: res.left + (res.width - this.defaultConfig.underLineWidth) / 2
					};
					// 运算完成之后，计算一次【滑块】的位置
					if (data.length - 1 === index) {
						this.tabToIndex();
					}
				}).exec();
			})
		},
		/**
		 * item 点击事件
		 * @param {Object} index
		 */
		onTabClick(index) {
			this.activeIndex = index;
			// 每次点击重新计算滑块的位置
			this.tabToIndex();
			// 发送一个通知,同ing之表示激活项发生变化了
			this.$emit("tabClick", index);
		},
		/**
		 * 根据当前的 activeIndex 计算滑块的滚动位置
		 */
		tabToIndex() {
			// 获取当前的 activeIndex
			const index = this.activeIndex;
			if (this.tabList.length) {
				this.slider = {
					left: this.tabList[index]._slider.left
				}
			}
			// 控制 scrollView 横向的滚动
			this.scrollLeft = this.activeIndex * this.defaultConfig.underLineWidth;
		}
	}
}
</script>

<style lang="scss" scoped>
.tab-container {
	font-size: $uni-font-size-base;
	height: 45px;
	line-height: 45px;
	background-color: $uni-bg-color;

	.tab-box {
		width: 100%;
		height: 45px;
		display: flex;
		position: relative;

		.scroll-view {
			white-space: nowrap;
			width: 100%;
			height: 100%;
			box-sizing: border-box;

			.scroll-content {
				width: 100%;
				height: 100%;
				position: relative;

				.tab-item-box {
					height: 100%;

					.tab-item {
						height: 100%;
						display: inline-block;
						text-align: center;
						padding: 0 15px;
						position: relative;
						color: $uni-text-color;

						&-active {
							color: $uni-text-color-active;
						}
					}
				}

				.under-line {
					height: 2px;
					width: 24px;
					background-color: $uni-text-color-active;
					border-radius: 3px;
					transition: .5s;
					position: absolute;
					bottom: 0;
				}
			}
		}
	}
}
</style>
